﻿/*
输入：
3
1 2
1 3
2 3
输出：
2 3
*/
// N个顶点和边
int N = int.Parse(Console.ReadLine());

// 并查集
int[] father = new int[N+1];

// 初始化并查集
void Init(int[] father)
{
    for (int i = 0; i < father.Length; i++) 
    {
        father[i] = i;
    }
}

int find(int[] father, int u) // 搜索根节点，并进行路径压缩
{
    return father[u] == u ? u : father[u] = find(father, father[u]);
}

void Join(int[] father, int u, int v) // 加入集合
{
    u = find(father, u);
    v = find(father, v);
    if (u == v) return;
    father[u] = v;
}

bool isSame(int[] father, int u, int v) // 判断是否在一个集合中
{
    u = find(father, u);
    v = find(father, v);
    return u == v;
}

// 记录各个顶点的入度
int[] inDegree = new int[N + 1];
List<(int, int)> edges = new List<(int, int)>(); // 记录各条边
int have2InDegree = 0;
// 接收输入
for (int i = 0; i < N; i++)
{
    string[] stStr = Console.ReadLine().Split(" ");
    int s = int.Parse(stStr[0]);
    int t = int.Parse(stStr[1]);
    inDegree[t]++;
    if (inDegree[t] >= 2) have2InDegree = t;
    edges.Add((s, t));
}

// 判断删除边，是否还是树
bool TryRemoveEdge(List<(int, int)> edges, int s, int t)
{
    Init(father);
    for (int i = 0; i < edges.Count; i++)
    {
        (int si, int ti) = edges[i];
        if (si == s && ti == t) continue;

        if (isSame(father, si, ti)) return false;
        Join(father, si, ti);
    }

    return true;
}

// 如果有两个入度
if (have2InDegree > 0)
{
    for (int i = edges.Count - 1; i >= 0; i++)
    {
        (int s, int t) = edges[i];
        if (t == have2InDegree && TryRemoveEdge(edges, s, t))
        {
            Console.WriteLine($"{s} {t}");
            return;
        }
    }
}
else
{
    Init(father);
    for (int i = 0; i < edges.Count; i++)
    {
        (int si, int ti) = edges[i];

        if (isSame(father, si, ti)) Console.WriteLine($"{si} {ti}");
        Join(father, si, ti);
    }
}
